package warehouse;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import javafx.application.Platform;

/**
 *
 * @author Razvan Manolescu & Adriana Ene
 */
public class Warehouse {

    public static Persistance persist;
    public static List<Index> indexSelectCache;
    public static Menu menu;
    public static Map<String, BloomFilterColumn> bloomFilterMap;

    public static void main(String[] args) throws Exception {
        persist = new Persistance();
        Platform.setImplicitExit(false);
        menu = new Menu();
        menu.setVisible(true);
        indexSelectCache = persist.refreshIndexSelectivity();
        
        Collections.sort(indexSelectCache);
//      
        bloomFilterMap = Util.createBloomFilterColumns(persist);
        
        loadPreCalc("columns.txt");

//       Tuple<String, Boolean> tuple = replaceAggregates("SELECT SUM(physical.height), COUNT(physical.wight) FROM physical");
//       
//        System.out.println("Remainign query " + tuple.getFirst());
//        System.out.println("Need to run " + tuple.getSecond());
        /* Set the Nimbus look and feel */

        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(ManagerCharts.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(ManagerCharts.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(ManagerCharts.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ManagerCharts.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

   
       
        /**
         * Aggregate replace example
         *
         */
        
        final String aggQuery = "SELECT SUM(discount.discount) , AVG(purchase_item.quantity) , discount.name FROM discount , purchase_item;";
        System.out.println("Exemplu inlocuire operatori agregare \nOriginal : "+aggQuery+"\n Inlocuit \n"+replaceAggregates(aggQuery)); 
        
        // Index selecitvity
        System.out.println("\nSelectivitate index \n\n "+indexSelectCache);
        buildTreeOutput();
       createShipmentStatistics();
       generateYearStatistic();
    }
    
    private static void buildTreeOutput() throws Exception{
        final ColumnTree tree = persist.buildTableTree( Constants.FACTS_TABLE);
        System.out.println(""+tree);
        final PrintWriter pr = new PrintWriter(Constants.FILE_ROOT + Constants.OUTPUT_PREVIEW_FILE_NAME);
        pr.print(tree.toJson());
        pr.close();        
    }
    
    private static void generateYearStatistic() throws Exception {
       final Map<Integer, List<int[]>> preList = persist.getShippingHistoricalInfoList();
       final PrintWriter pr = new PrintWriter(Constants.FILE_ROOT + Constants.OUTPUT_PREVIEW_FILE_NAME_STATISTIC);
       final JSONArray object = new JSONArray();
       
       for(Entry<Integer, List<int[]>> entry : preList.entrySet()){
           if(entry.getValue().size() < 2)
               continue;
           
           final JSONObject nation = new JSONObject();

           final JSONArray incomes = new JSONArray();
           final JSONArray populations = new JSONArray();    
           final JSONArray lifeExps = new JSONArray();

           for(int[] a : entry.getValue()){
               final JSONArray income = new JSONArray();
               income.put(a[0]);
               income.put(a[0]-a[2]+ a[1]*100 * (a[2]%100+1));

               final JSONArray population = new JSONArray();
               population.put(a[0]);
               population.put((a[2]/a[1])*20000*(entry.getKey()%10+1));

               final JSONArray lifeExp = new JSONArray();
               lifeExp.put(a[0]);
               lifeExp.put(a[2]/(a[1]*15) +35);
               
               incomes.put(income);
               populations.put(population);
               lifeExps.put(lifeExp);
            }

           nation.put("name", ""+entry.getKey());
           nation.put("region", ""+entry.getKey());
           nation.put("income", incomes);
           nation.put("population", populations);
           nation.put("lifeExpectancy", lifeExps);

           object.put(nation);
       }
       pr.print(object);
       pr.close();     
    }
    
    private static void createShipmentStatistics(){
        PrintWriter pr = null;
        try {
            pr = new PrintWriter(Constants.FILE_ROOT + Constants.OUTPUT_SHIPMENT_STATISTICS);
            final String statistcs = persist.getShippingHistoricalInfo();
            pr.print("year,age,sex,people\n");
            pr.print(statistcs);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
        finally{
            pr.close();
        }
    }
    
    public static void getGranularity(String[] dimColumns){
        /*
         * Goes through all dim columns tree and finds the one with the highest level
         * Minimize inner joins -
         * If column is from a child node, candidates are counted and consolidated for promotion
         */
    }
    
    /**
     * Creates datamart
     *
     * @param name Datamart name
     * @param query SQL query
     */
    public static void createDatamart(String name, String query) {
        name = Constants.DATAMART_PREFIX + name;
        //String tables = query.split("FROM")[1].split("WHERE")[0].split("GROUP")[0].split("ORDER")[0].split(";")[0].trim();
        final Map<String, List<String>> map = Util.parseQuery(query);
        //System.out.println("" + tables);
        persist.createDataMart(name, map, query.split(";")[0]);
    }

    public static void loadPreCalc(String columnFilePath) throws Exception {
        BufferedReader br = new BufferedReader(new FileReader(columnFilePath));

        String line;
        while ((line = br.readLine()) != null) {
            String s[] = line.split(" ");
            persist.calcCount(s[0], s[1]);
        }

        br.close();
    }

    public static void executeQuery(String query, String[] tables, boolean useDataMarts,
            boolean replaceAggregate, boolean orderIndexes) {
        List<String[]> data = null;
        if (useDataMarts) {
            data = persist.getDatamart(tables);
        }

//        if (data == null || !useDataMarts) {
//            if (replaceAggregate) {
//                String tuple = replaceAggregates(query);
//                if ( && orderIndexes) {
//                }
//            }
//        }

        if (orderIndexes) {
        }
    }

    public static void addSorted(List<Integer> selects, List<String> names, int select, String name) {
        int pos = -1;
        int i = 0;

        if (selects.size() > 0) {
            pos = selects.get(i);
            while (pos < select) {

                i++;
                if (i < selects.size()) {
                    pos = selects.get(i);
                } else {
                    break;
                }
            }
        }

        selects.add(i, select);
        names.add(i, name);
    }

    public static String bloomFilter(final String query) {
        final String defRetString = "SELECT NULL from dual;";
        
        if(!(query.contains("WHERE") || query.contains("where")))
            return query;
        
        final String sp[] = query.split("(where|WHERE)");
        if(sp[1].contains("(OR|or)"))
            return query;
        
        final String spA[] = sp[1].split("(AND|and)");
        for(String s : spA){
            if(!s.contains("="))
                continue;
            
            final String[] spE = s.split("=");
            if(spE == null || spE.length < 2)
                continue;
            
            final String col = spE[0].contains("\\.") ? spE[0].split("\\.")[1].trim() : spE[0].trim();
            Integer value = null;
            
            try{
                value = Integer.valueOf(spE[1].trim());
            }catch(Throwable t){
                t.printStackTrace();
            }
            
            if(value == null)
                continue;
            
            if(bloomFilterMap.get(col) != null && !bloomFilterMap.get(col).couldContain(value)){
                return defRetString;
            }
        }
        
        return query;
    }
    
    public static String orderIndexes(String query) {
        String[] aux = query.split("(FROM|from)");
        String fromStr = aux[1];
        String[] columns = aux[0].split("(SELECT|select)")[1].split(",");
        StringBuilder sb = new StringBuilder("SELECT ");

        List<Integer> selects = new ArrayList<Integer>();
        List<String> names = new ArrayList<String>();
        int indx;

        for (String column : columns) {
            column = column.trim();
            aux = column.split("\\.");
            if ((indx = indexSelectCache.indexOf(new Index(0, aux[0], aux[1]))) > 0) {
                addSorted(selects, names, indx, column);
            } else {
                addSorted(selects, names, Integer.MAX_VALUE, column);
            }
        }

        int i;
        for (i = 0; i < names.size() - 1; i++) {
            sb.append(names.get(i));
            sb.append(", ");
        }
        sb.append(names.get(i));

        sb.append(" FROM ");
        sb.append(fromStr);

        return sb.toString();
    }

    public static String replaceAggregates(final String query) {
        if(query.contains("WHERE") || query.contains("where"))
            return query;
            
        String[] aux = query.split("(FROM|from)");
        String fromStr = "FROM "+aux[1];
        String[] columns = aux[0].split("(SELECT|select)")[1].split(",");
        StringBuilder sb = new StringBuilder("SELECT ");

        int replaceCount = 0;

        for (String column : columns) {
            if (column.contains("COUNT(")) {
                aux = column.split("\\(")[1].split("\\)")[0].split("\\.");

                Tuple t = persist.getCount(aux[0], aux[1]);

                Long count = (Long) t.getFirst();
                sb.append(count);
                sb.append(",");
                ++replaceCount;
                continue;
            }

            if (column.contains("SUM(")) {
                aux = column.split("\\(")[1].split("\\)")[0].split("\\.");

                Tuple t = persist.getCount(aux[0], aux[1]);

                Long sum = (Long) t.getSecond();
                sb.append(sum);
                sb.append(",");
                ++replaceCount;
                continue;
            }

            if (column.contains("AVG(")) {
                aux = column.split("\\(")[1].trim().split("\\)")[0].trim().split("\\.");

                Tuple t = persist.getCount(aux[0], aux[1]);

                Long count = (Long) t.getFirst();
                Long sum = (Long) t.getSecond();

                sb.append((double)sum / count);
                sb.append(",");
                ++replaceCount;
                continue;
            }

            sb.append(column);
            sb.append(",");
        }

        // delete trailing ','
        sb.deleteCharAt(sb.length() - 1);

        sb.append(" ");
        sb.append(fromStr);
        
        return sb.toString();
    }

}
